home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
ddj9304.zip
/
1993-APR.ZIP
/
FRAG.ASC
< prev
next >
Wrap
Text File
|
1993-02-17
|
16KB
|
683 lines
_MEASURING FRAGMENTATION_
by James Harrington
[LISTING ONE]
/* This module contains a generic function that calculates a fragmen-
tation index. This index depends on the numbers of used and free
block, the largest number of bytes that can currently be allocated
in a contiguous block, and the total amount of free memory.
Several functions declared as "extern" will be found in other
modules, where each module calculates values as appropriate for
a particular memory manager.
*/
#include <stdio.h>
double fragindex( void );
double getHeapSizeF( void );
double getBreakupF( void );
double getLargeFreeF( void );
double getWorstCase( void );
extern double getWorstCase( void ); /* In manager-specific module */
extern long getnfreeblks( void ); /* In manager-specific module */
extern long getnusedblks( void ); /* In manager-specific module */
extern long getlargest( void ); /* In manager-specific module */
extern long gettotalfree( void );
/*********************************************************************
*
* double fragindex( void )
*
* This procedure returns a relative value that reflects the degree of
* heap fragmentation. It is calculated as follows:
*
* frag_index = BreakupFactor / LargeFreeFactor
*
* BreakupFactor = number of free blocks-1 / number of used
* blocks+1, where the free memory above utilized heap is
* counted as a free block.
* LargeFreeFactor = size of largest block that can be success-
* fully allocated / total amount of unused memory,
* including overhead.
*
* maximal fragmentation occurs when every other block is free, all
* blocks are of the minimal size, and all of memory has been filled
* with used:free block pairs.
*
* If adjacent free blocks are allowed to exist, maximal fragmentation
* occurs when every block is free (except perhaps for one, and not
* counting any blocks allocated by startup code), all blocks are of
* the minimal size, and all of memory has been filled with free
* blocks.
*
* Returns -1 in case of error condition - corrupt heap or setdos()
* not called in an MSC program. setdos() is required only if compar-
* ing with other memory managers.
*
*********************************************************************/
double fragindex( void )
{
double breakupF, largeFreeF;
breakupF = getBreakupF();
largeFreeF = getLargeFreeF();
if( breakupF<0 || largeFreeF<0 )
return( -1 );
if( !largeFreeF )
return( 0 );
else
return ( breakupF/largeFreeF );
}
/*********************************************************************
*
* getBreakupF
*
* Returns the BreakupFactor for use in the fragindex function.
*
*********************************************************************/
double getBreakupF( void )
{
long nfree, nused;
nfree = getnfreeblks();
nused = getnusedblks();
if( nfree<=0 )
return(nfree);
return (double)(--nfree) / (double)(++nused);
}
/*********************************************************************
*
* getLargeFreeF
*
* Returns the LargeFreeFactor for use in the fragindex function.
*
* Returns -1 if error in heapwalk, 0 if is no free memory
*
*********************************************************************/
double getLargeFreeF( void )
{
double sizelargest;
sizelargest = (double)getlargest();
if( sizelargest < 0 )
return( -1 );
if( !sizelargest )
return( 0 );
else
return (sizelargest / (double)gettotalfree());
}
[LISTING TWO]
/* Provides Borland-specific versions of functions called by fragindex() */
/* Assumes no UMBs, etc., are available to malloc() */
#include <alloc.h>
#include <stdlib.h>
#include <stdio.h>
long gettotalfree( void );
long getnusedblks( void );
long getnfreeblks( void );
long getlargest( void );
void setdos( void );
/*********************************************************************
*
* getlargest( void );
*
* Returns a number of bytes, the size of the largest block of
* contiguous free memory that can be successfully allocated from the
* heap with farmalloc(), malloc(), or _halloc().
*
*********************************************************************/
long getlargest( void )
{
struct farheapinfo hinfo;
long size = 0;
hinfo.ptr = NULL;
while( heapwalk( &hinfo ) == _HEAPOK ){
if( !hinfo.in_use )
size = max( size, hinfo.size );
}
size = max( size, farcoreleft()-4 );
return( size );
}
/*********************************************************************
*
* getnfreeblks( void );
*
* Returns the number of free blocks in the heap. Doesn't count memory
* above utilized heap.
*
* Returns -1 if heap is corrupt
*
*********************************************************************/
long getnfreeblks( void )
{
struct farheapinfo hinfo;
register int count = 0;
if( heapcheck() < 0 )
return( -1 );
hinfo.ptr = NULL;
while( heapwalk( &hinfo ) == _HEAPOK ){
if( !hinfo.in_use )
count++;
}
/* ret count+1 to count coreleft() memory */
return (long) ++count;
}
/*********************************************************************
*
* getnusedblks( void );
*
* Returns the number of allocated blocks in the heap.
*
*********************************************************************/
long getnusedblks( void )
{
struct farheapinfo hinfo;
register int count = 0;
hinfo.ptr = NULL;
while( heapwalk( &hinfo ) == _HEAPOK ){
if( hinfo.in_use )
count++;
}
return (long) count;
}
/*********************************************************************
*
* gettotalfree( void );
*
* Returns the total amount of free memory.
*
*********************************************************************/
long gettotalfree( void )
{
struct farheapinfo hinfo;
long size=0;
hinfo.ptr = NULL;
while( heapwalk( &hinfo ) != _HEAPEND ){
if( !hinfo.in_use )
size+=(hinfo.size+4);
}
size += farcoreleft();
return (long)size;
}
/*********************************************************************
*
* setdos( void );
*
* For sake of compatibility with fragmic.c
*
*********************************************************************/
void setdos( void )
{
}
[LISTING THREE]
/* Provides Microsoft C-specific versions of functions used in
calculating a fragmentation index. */
/* Assumes no UMBs, etc., are available to malloc() */
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#define LOWSEGS 100
/* signed int, must be > 0 */
/* represents the max number of
free DOS blocks expected at
time of program startup */
#define NDOS 200
/* signed int, must be > 0 */
/* affected by value of
_amblksize variable - smaller
val means larger NDOS req'd */
/* represents max number of
free DOS blocks
expected */
int nsegs, _callflag;
unsigned _far dosseg_array[ LOWSEGS ]; /* saves segs for findfrag() */
unsigned _far seg_array[ NDOS ]; /* saves segs for setdos() */
void limitheap( void );
void freesegs( void );
long countdos( void );
long bigdos( void );
long dossize( void );
long gettotalfree( void );
long getnusedblks( void );
long getnfreeblks( void );
long getlargest( void );
void setdos( void );
void freedos( int count );
/* Note: _dos_allocmem() is a compiler runtime library function that
allocates a block of memory directly from MS-DOS through int 21h
fxn. 48h. You request a number of paragraphs (blocks of 16 bytes).
Requesting 0xffff paragraphs will result in an error return, with
the size of the largest allocable block, in paragraphs, being
returned in the variable whose address is passed as the second
parameter to _dos_allocmem(). _dos_freemem() frees the blocks
allocated through _dos_allocmem(), via int 21h fxn 49h.
*/
/*********************************************************************
*
* getlargest( void );
*
* Returns a number of bytes, the size of the largest block of contigu-
* ous free memory that can be successfully allocated from the heap
* with fmalloc(), malloc() (in far data memory models), or _halloc().
*
* Returns -1 if error
*
*********************************************************************/
long getlargest( void )
{
struct _heapinfo hinfo;
int herr;
long maxsize = 0;
long tsize = 0;
char first = 0;
unsigned seg = 0;
maxsize = bigdos();
/* Get largest free */
hinfo._pentry = NULL;
while( (herr=_heapwalk( &hinfo )) != _HEAPEND && herr==_HEAPOK){
/* if is a used block... */
if( hinfo._useflag ){
first = 0;
seg = (unsigned)(((unsigned long)hinfo._pentry)>>16);
}
/* but if is a free block... */
else{
/* if last block was a used block */
if( !first ){
tsize = hinfo._size;
/* If switch DOS blocks */
if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
!= seg )
seg =
(unsigned)(((unsigned long)hinfo._pentry)>>16);
maxsize = max( maxsize, tsize );
first=1;
}
/* if last block was a free block too */
else{
/* If switch DOS blocks */
if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
!= seg ) {
seg =
(unsigned)(((unsigned long)hinfo._pentry)>>16);
tsize = hinfo._size;
}
else
tsize += (hinfo._size+2);
maxsize = max( maxsize, tsize );
}
}
}
return( herr==_HEAPEND?maxsize:-1 );
}
/*********************************************************************
*
* long bigdos( void )
*
* Returns the size of the largest block of available DOS memory.
*
*********************************************************************/
long bigdos( void )
{
unsigned size;
_dos_allocmem( 0xffff, &size );
return( (long)(size-1) * 16L ); /* Size of largest allocable
block */
}
/*********************************************************************
*
* getnfreeblks( void );
*
* Returns the number of free blocks in the heap, and assumes adjacent
* free blocks in the same DOS block can be combined.
*
* Returns -1 in case of error
*
*********************************************************************/
long getnfreeblks( void )
{
struct _heapinfo hinfo;
int herr;
unsigned seg;
long count = 0;
char first = 0;
/* error if didn't call setdos() */
if( !_callflag )
return( -1 );
hinfo._pentry = NULL;
while( (herr=_heapwalk( &hinfo )) != _HEAPEND && herr==_HEAPOK){
/* if is a used block... */
if( hinfo._useflag ){
first = 0;
seg = (unsigned)(((unsigned long)hinfo._pentry)>>16);
}
/* but if is a free block... */
else{
/* if last block was a used block */
if( !first ){
count++;
/* If switch DOS blocks */
if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
!= seg )
seg =
(unsigned)(((unsigned long)hinfo._pentry)>>16);
}
/* if last block was a free block too */
else{
/* If switch DOS blocks */
if( (unsigned)(((unsigned long)hinfo._pentry)>>16)
!= seg ){
seg =
(unsigned)(((unsigned long)hinfo._pentry)>>16);
count++;
}
}
}
}
return( herr==_HEAPEND?(count+countdos()):-1 );
}
/*********************************************************************
*
* int countdos( void )
*
* Counts the number of free DOS blocks, up to NDOS blocks
*
*********************************************************************/
long countdos( void )
{
int count;
for( count=0; count<NDOS; count++ ){
_dos_allocmem( 0xffff, &seg_array[count] );
if( seg_array[count] )
_dos_allocmem( seg_array[count], &seg_array[count] );
else
break;
}
/* count is the number of allocated blocks */
freedos(count);
if( count == NDOS ){
printf("\nToo many DOS blocks; increase value of NDOS.");
exit(0);
}
return count;
}
/*********************************************************************
*
* getnusedblks( void );
*
* Returns the number of allocated blocks in the heap.
*
*********************************************************************/
long getnusedblks( void )
{
struct _heapinfo hinfo;
long count = 0;
hinfo._pentry = NULL;
while( _heapwalk( &hinfo ) != _HEAPEND ){
if( hinfo._useflag )
count++;
}
return count;
}
/*********************************************************************
*
* gettotalfree( void );
*
* Returns the total amount of free memory.
*
*********************************************************************/
long gettotalfree( void )
{
struct _heapinfo hinfo;
long size=0;
hinfo._pentry = NULL;
while( _heapwalk( &hinfo ) != _HEAPEND ){
if( !hinfo._useflag )
size+=(hinfo._size+2);
}
return size + dossize();
}
/*********************************************************************
*
* dossize( void )
*
* Counts the number of bytes in free DOS blocks, up to NDOS DOS
* blocks. Includes 16 bytes overhead for each block.
*
*********************************************************************/
long dossize( void )
{
unsigned seg_array[NDOS];
int count;
long size = 0;
for( count=0; count<NDOS; count++ ){
_dos_allocmem( 0xffff, &seg_array[count] );
if( seg_array[count] ){
size += ((long)seg_array[count]+1)*16L;
_dos_allocmem( seg_array[count], &seg_array[count] );
}
else
break;
}
/* count is the number of allocated blocks */
freedos(count);
if( count == NDOS ){
printf("\nToo many DOS blocks; increase value of NDOS.");
exit(0);
}
return( size );
}
/*********************************************************************
*
* void freedos( int count )
*
* Frees segments stored in seg_array[].
*
* Parm "count" is number of stored segments.
*
*********************************************************************/
void freedos( int count )
{
int i;
if( !count )
return;
for( i=0; i<count; i++ )
_dos_freemem( seg_array[i] );
}
/*********************************************************************
*
* setdos( void );
*
*********************************************************************/
void setdos( void )
{
atexit( freesegs );
limitheap();
_callflag++;
}
/*********************************************************************
*
* limitheap()
*
* This function allocates all the DOS blocks besides the one
* immediately above the program block. Assumes that the one above the
* program block is the biggest free DOS block.
*
*********************************************************************/
void limitheap(void)
{
/* nsegs = 0 at start */
while( nsegs<LOWSEGS ){
_dos_allocmem( 0xffff, &dosseg_array[nsegs] );
if( dosseg_array[nsegs] ){
_dos_allocmem( dosseg_array[nsegs],&dosseg_array[nsegs] );
nsegs++;
}
else
break;
}
if( nsegs == LOWSEGS ){
_dos_freemem( dosseg_array[0] );
printf("\nToo many free DOS blocks at start; ");
printf("\nincrease value of of LOWSEGS.");
exit(0);
}
if( nsegs )
_dos_freemem( dosseg_array[0] );
}
void freesegs(void)
{
int i;
if( !_callflag )
printf("\nerror: didn't call setdos()");
else{
if( nsegs>1 ){
for( i=1; i<nsegs; i++ )
_dos_freemem( dosseg_array[i] );
}
}
}